#pragma once

#include <functional>

#include "uncopyable.hpp"
#include "Socket.hpp"

using namespace socket_ddsm;

// Tcp服务器，接受用户发送的信息，发回消息
class TcpServer : public uncopyable
{
    // 回调函数的类型
    using service_io_t = std::function<void(SockSPtr,const Inet &)>;

    // 使用多线程解决服务器无法同时服务多个客户端的问题----原生线程的使用
    // 创建的目的是便于传递参数
    struct ThreadData
    {
        TcpServer *_self;
        SockSPtr _sockfd;
        Inet _addr;

        ThreadData(TcpServer *self, SockSPtr sockfd, const Inet &addr)
            : _self(self), _sockfd(sockfd), _addr(addr)
        {
        }
        ~ThreadData()
        {
        }
    };

public:
    // 在构造的时候，传入回调函数即可，实现高度解耦
    TcpServer(service_io_t service,uint16_t port = gport)
        : _port(port), _listensock(std::make_shared<TcpSocket>()), _isrunning(false), _service(service)
    {
        // 面向对象式的创建tcp socket
        _listensock->BuildListenSocket(port);
    }

    void Start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            Inet client;
            SockSPtr newsock = _listensock->Accepter(&client);
            if (newsock == nullptr)
                continue;
            LOG(DEBUG, "get a new link,client info: %s,sockfd is %d\n", client.UniqueName().c_str(), newsock->GetSocket());

            // 5.提供服务(服务器需要能够同时为多个客户端提供服务)
            /* 使用多线程解决服务器无法同时服务多个客户端的问题----原生线程的使用
                创建一个新线程来提供服务
            */
            pthread_t tid;
            ThreadData *td = new ThreadData(this, newsock, client);
            pthread_create(&tid, nullptr, Excute, (void *)td);
        }
        _isrunning = false;
    }

    static void *Excute(void *args) // static 防止this指针干扰函数类型
    {
        // 新线程解除与主线程的等待关系，主线程不再需要等待新线程
        pthread_detach(pthread_self());
        // 目的是调用Service---static内部无法获取对象，需要传递进来--所以通过一个设计的ThreadData类把需要的参数传递进来
        ThreadData *ptd = static_cast<ThreadData *>(args);
        // 回调
        ptd->_self->_service(ptd->_sockfd, ptd->_addr);
        // 面向对象,关闭sockfd
        ptd->_sockfd->Close();
        delete ptd;
        return nullptr;
    }

    ~TcpServer() {}

private:
    uint16_t _port;       // 端口
    SockSPtr _listensock; // 自定义实现的socket类,交给智能指针管理
    bool _isrunning;
    service_io_t _service;
};
